/**
 * @author xuyh0817
 * @email xuyh0817@foxmail.com
 * @date 2022-02-15 23:45
 * @version 2.0.0
 * @doc todo
 * @website todo
 * @remark  如果要分发源码，需在本文件顶部保留此文件头信息！！
 */

import {cloneDeep} from 'lodash'
import {CUSTOM_EVENT_TYPE} from '../../constants'
import {flatFormOptions, randomString} from '../../utils'

/**
 * 表单方法
 */
export default {
  /**
   * 禁用组件
   *
   * @param{Array} props | layoutName 禁用组件的字段prop 或者 layoutName
   */
  disabledComponents() {
    const props = [...arguments]
    this.changeFormOptions(props, 'disabled', true)
  },
  /**
   * 启用组件
   *
   * @param{Array} props | layoutName 启用组件的字段prop 或者 layoutName
   */
  enabledComponents() {
    const props = [...arguments]
    this.changeFormOptions(props, 'disabled', false)
  },
  /**
   * 显示组件
   *
   * @param{Array} props | layoutName 显示组件的字段prop 或者 layoutName
   */
  showComponents() {
    const props = [...arguments]
    this.changeFormOptions(props, 'show', true)
  },
  /**
   * 隐藏组件
   *
   * @param{Array} props | layoutName 隐藏组件的字段prop 或者 layoutName
   */
  hideComponents() {
    const props = [...arguments]
    this.changeFormOptions(props, 'show', false)
  },

  /**
   * 清除验证
   *
   * @param{String} prop 字段
   */
  clearValidate(prop) {
    this.$refs.xFormModel.clearValidate(prop)
  },
  /**
   * 提交form
   */
  submitForm() {
    this.validateForm().then(res => {
      this.$emit(CUSTOM_EVENT_TYPE.FORM_SUBMIT, res)
    })
  },
  /**
   * 重置form
   */
  resetForm() {
    this.$refs.xFormModel.resetFields()
  },
  // //////////////////用户可以使用的方法 【end】///////////////////////////////

  /**
   * 切换组件   【组件方法，不建议使用】
   * @param{Array} props 切换的字段
   * @param{String} type 类型
   * @param{Boolean,String,Number,Object} value 填充的值
   */
  changeFormOptions(props, type = 'show', value = false) {
    if (!(props instanceof Array)) {
      throw new Error('props 非数组类型')
    }
    const {flatFormOptionMap} = this
    for (const option of Object.values(flatFormOptionMap)) {
      if (['show', 'disabled'].includes(type)) {
        for (const prop of props) {
          if (option.formItem.prop === prop || option.formItem.xRawProp === prop || option.attrs.layoutName) {
            if (type === 'show') {
              this.$set(option, 'xShow', value)
            }
            if (type === 'disabled') {
              this.$set(option.attrs, 'disabled', value)
            }
          }
        }
      }
    }
  },

  /**
   * 校验表单 【组件方法，不建议使用】
   */
  validateForm() {
    return new Promise((resolve) => {
      this.$refs.xFormModel.validate(valid => {
        if (valid) {
          const {formData} = this
          resolve(formData)
        } else {
          this.$message.error('请确认填写内容！')
          return false
        }
      })
    })
  },
  /**
   * 组件的change事件 【组件方法，不建议使用】
   * @param{Object} event 组件传递的属性
   */
  changeHandler(event) {
    const {formChangeValidateField, formData: selfFormData} = this
    if (formChangeValidateField) {
      // 触发验证
      this.$refs.xFormModel.validateField(event.prop)
    }
    // 触发change事件
    this.$emit(CUSTOM_EVENT_TYPE.CHANGE, event)
    const {value, formItem} = event
    if (formItem && formItem.prop) {
      const formData = {}
      // 是否为增强的属性
      if (formItem.xEnhanceProp) {
        const data = {}
        // 增强属性，进行设置
        this.arrKeyGenerateObj(formItem.xPropKeys, value, data)
        for (const key in data) {
          if (selfFormData[key] !== data[key]) {
            // 对象数据，进行合并
            formData[key] = Object.assign({}, cloneDeep(selfFormData[key]), data[key])
          }
        }
      }
      if (selfFormData[formItem.prop] !== value) {
        // 普通属性进行设置
        formData[formItem.prop] = value
      }
      if (Object.keys(formData).length !== 0) {
        // 更新表单数据
        this.updateForm(Object.assign({}, cloneDeep(selfFormData), formData))
      }
    }

  },
  /**
   * 组件的自定义事件 【组件方法，不建议使用】
   * @param{Object} event 组件传递的属性
   */
  customEventHandler(event) {
    const {formData: selfFormData} = this
    const {type, value} = event
    // 设置关联属性的值
    if (type === CUSTOM_EVENT_TYPE.ASSOCIATION_CHANGE_EVENT) {
      const formData = {}
      for (const key in value) {
        if (value[key] !== selfFormData[key]) {
          formData[key] = value[key]
        }
      }
      if (Object.keys(formData).length !== 0) {
        // 更新表单数据
        this.updateForm(Object.assign({}, cloneDeep(selfFormData), formData))
      }
    }
    this.$emit(CUSTOM_EVENT_TYPE.CUSTOM_EVENT, event)
  },
  /**
   * 更新表单事件 【组件方法，不建议使用】
   * @param{Object} form 表单数据
   */
  updateForm(form) {
    // change 事件
    this.$emit(CUSTOM_EVENT_TYPE.FORM_CHANGE, form)
  },
  /**
   * 初始化表单数据 【组件方法，不建议使用】
   */
  initFormData(flatFormOptionMap) {
    if (!flatFormOptionMap || Object.keys(flatFormOptionMap).length === 0) {
      return
    }
    const {formData: selfFormData} = this
    const formData = {}
    // 复制组件配置数据
    Object.keys(flatFormOptionMap).forEach((key) => {
      const {attrs, isLayout, formItem} = flatFormOptionMap[key]
      if (!isLayout && !!formItem && !!formItem.prop) {
        const value = this.getFormItemValue(attrs, formItem.prop)
        // 是否为增强的属性
        if (formItem.xEnhanceProp) {
          const data = {}
          // 增强属性，进行设置
          this.arrKeyGenerateObj(formItem.xPropKeys, value, data)
          for (const key in data) {
            if (selfFormData[key] !== data[key]) {
              formData[key] = data[key]
            }
          }
        }
        if (selfFormData[formItem.prop] !== value) {
          // 普通属性进行设置
          formData[formItem.prop] = value
        }
      }
      if (isLayout) {
        // 设置默认layoutName
        attrs.layoutName = attrs.layoutName || randomString(12)
      }
    })
    if (Object.keys(formData).length !== 0) {
      // 更新表单数据
      this.updateForm(Object.assign({}, cloneDeep(selfFormData), formData))
    }
  },
  /**
   * 初始化表单配置项 【组件方法，不建议使用】
   */
  initActiveFormOptions() {
    const {formOptions, formDisabled, activeFormOptions} = this
    const options = []
    // 组件配置不正确，返回为空
    if (!formOptions) {
      return options
    }
    // 复制组件配置数据
    const cloneDeepFormOptions = cloneDeep(formOptions)
    const flatFormOptionMap = {}
    flatFormOptions(cloneDeepFormOptions, flatFormOptionMap)
    // 配置属性遍历初始化
    for (const key of Object.keys(flatFormOptionMap)) {
      const item = flatFormOptionMap[key]
      // 组件展示属性设置
      if (typeof (item.xShow) !== 'boolean') {
        item.xShow = true
      }
      // 初始化属性
      item.attrs = item.attrs || {disabled: false}
      // 全部禁用
      if (formDisabled) {
        item.attrs.disabled = true
      }
      // 布局设置配置
      item.layout = item.layout || {
        span: 24,
        offset: 0
      }
      // 非布局组件，进行初始化设置formItem
      if (!item.isLayout) {
        // 初始化formItem
        item.formItem = item.formItem || {prop: `prop${Date.now}`}
        // 处理prop
        this.formItemPropPostProcessor(item.formItem)
      }
    }
    for (const option of cloneDeepFormOptions) {
      options.push(option)
    }
    activeFormOptions.splice(0, activeFormOptions.length, ...options)
    return flatFormOptionMap
  },
  /**
   * 处理没项的prop 【组件方法，不建议使用】
   * @param{Object} formItem 表单项数据
   */
  formItemPropPostProcessor(formItem) {
    // 处理prop 如果prop为 user.name的形式将转换为 userName
    // 同时会增加新的属性 originalProp 存储原来的 user.name
    if (!!formItem && !!formItem.prop) {
      // toString 防止有使用非字符串类型的数据
      const prop = formItem.prop.toString()
      // 将数据进行转为String
      formItem.prop = prop
      // 截取内容
      const split = prop.split('.')
      // 存储所有的属性key 例如 user.name =>  ['user','name']
      const propKeys = []
      if (split.length > 1) {
        let postProp = ''
        for (let i = 0; i < split.length; i++) {
          let tmp = split[i]
          if (tmp.length > 0) {
            tmp = tmp.toString()
            tmp = tmp.trim()
            propKeys.push(tmp)
            if (i !== 0) {
              // 全部转成小写
              tmp = tmp.toLowerCase().trim()
              // 首字符大写
              tmp = tmp.charAt(0).toUpperCase() + tmp.slice(1)
            }
          }
          // 属性拼接
          postProp += tmp
        }
        if (postProp.length > 0 && split.length === propKeys.length) {
          // 原始值赋值到 originalProp
          formItem.xRawProp = prop
          // 记录原始key
          formItem.xPropKeys = propKeys
          // 表示增强prop
          formItem.xEnhanceProp = true
          // 新值赋值到prop
          formItem.prop = postProp
        } else {
          throw new Error(`${prop}属性值错误，请确认`)
        }
      }
    }
  },
  /**
   * 根据key 生成对象
   *
   * @param {Array} arr key数组
   * @param {[String | Number | Object]} defaultValue 默认值
   * @param {Object} form 当前form
   * @return {Object}  多层嵌套对象
   */
  arrKeyGenerateObj(arr, defaultValue, form) {
    let parent = form
    for (let i = 0; i < arr.length; i++) {
      const key = arr[i]
      if (!parent[key]) {
        parent[key] = {}
      }
      if (i === arr.length - 1) {
        parent[key] = defaultValue
      } else {
        parent = parent[key]
      }
    }
  },
  /**
   * 获取表单项的默认值 【组件方法，不建议使用】
   * @param{Object} attrs 表单项数据
   * @param{String} prop prop属性
   */
  getFormItemValue(attrs, prop) {
    const {formData: selfFormData} = this
    // 优先加载 this.formData中的值
    if (selfFormData[prop]) {
      return selfFormData[prop]
    }
    // 设置默认值
    if (!!attrs && (!!attrs.value || attrs.checked !== undefined)) {
      // 再加载formOptions中的值
      if (attrs.value !== undefined) {
        return attrs.value
      } else if (attrs.checked !== undefined) {
        return attrs.checked
      }
    }
    return null
  }
}
